//
//  File_System_Manager.cpp
//  LearningOops
//
//  Created by Swetha Patnala on 4/14/13.
//  Copyright (c) 2013 Swetha Patnala. All rights reserved.
//


#include<iostream>

#include <string>
#include<vector>
#include <sstream>
#include<streambuf>

#include "File_System_Manager.h"
using namespace std;

File_System_Manager* File_System_Manager::Instance = NULL;

File_System_Manager* File_System_Manager::getInstance() {
    if (!File_System_Manager::Instance) {
        File_System_Manager::Instance = new File_System_Manager;
    }
    
    return File_System_Manager::Instance;
    
}

File_System_Manager::File_System_Manager() {
    
    
    super_block = new super_block_structure;
    super_block->file_system_name = (char*)"cmpe142";
    super_block->num_of_inodes = NUM_OF_INODES;
    super_block->num_of_datablocks = NUM_OF_DATABLOCKS;
    super_block->num_of_unallocated_datablocks = NUM_OF_DATABLOCKS;
    super_block->num_of_unallocated_inodes = NUM_OF_INODES;
    super_block->inode_counter = 0;
    super_block->datablock_counter = 0;
    super_block->first_block_of_inode = 3;
    super_block->first_block_of_data = 128;
    super_block->magic_number = (char*) " 0xEF53 ";
    // cout << "Success";
    
    
    int inode_bitmap[NUM_OF_INODES+1];
    fill_n(inode_bitmap, NUM_OF_INODES+1, 0); // initializing all the inodes as free 0 ;
    //if any inode is allocated , it would be initialized to 1
    
    int data_bitmap[NUM_OF_DATABLOCKS+1];
    fill_n(data_bitmap, NUM_OF_DATABLOCKS+1, 0); // initializing all the datablocks as free 0 ;
    //if any datablock is allocated , it would be initialized to 1
    
    for (int i = 0 ; i < NUM_OF_INODES +1 ; i++){
        inode_array[i]= new Inode();
    }
    
    
    
}

File_System_Manager::~File_System_Manager(){
    
    delete super_block;
    
}

void File_System_Manager:: printSuperBlock(){
    //cout << "Super Block Information"<<endl;
    cout <<"File System Name               : " << super_block->file_system_name <<endl;
    cout <<"Total Num of Inodes            : " << super_block->num_of_inodes <<endl;
    cout <<"Total Num of datablocks        : " << super_block->num_of_datablocks<<endl;
    cout <<"Num of Allocated Inodes        : " << super_block->inode_counter<<endl;
    cout <<"Num of Allocated datablocks    : " << super_block->datablock_counter<<endl;
    cout <<"Num of Unallocated Inodes      : " << super_block->num_of_unallocated_inodes<<endl;
    cout <<"Num of Unallocated datablocks  : " << super_block->num_of_unallocated_datablocks<<endl;
    cout <<"First Block of Inode           : " << super_block->first_block_of_inode <<endl;
    cout <<"First Block of Data            : " << super_block->first_block_of_data<<endl;
    cout <<"Magic number                   : " << super_block->magic_number;
    cout <<"-----------------------------------------------------------"<<endl;
    
    
}

void File_System_Manager::printInodeBitMap(){
    
    for(int i =1 ; i < 10 ; i++){
        cout << inode_bitmap[i]<<endl;
    }
    
    
}

void File_System_Manager::printDataBitMap(){
    for(int i =1 ; i < 10 ; i++){
        cout << data_bitmap[i]<<endl;
    }
    
}

int File_System_Manager:: decrement_num_of_unallocated_inodes(){
    
    if (super_block->num_of_unallocated_inodes <=  0 ){
        return -1;
    }
    super_block->num_of_unallocated_inodes--;
    return 0;
}

int File_System_Manager:: decrement_unallocated_datablock_num(int num_of_blocks){
    
    if (super_block->num_of_unallocated_datablocks <=  0){
        return -1;
    }
    
    int num = (super_block->num_of_unallocated_datablocks) - num_of_blocks;
    super_block->num_of_unallocated_datablocks = num;
    return 0;
}

int File_System_Manager:: increment_datablock_num(int num_of_blocks){
    
    int num = (super_block->num_of_unallocated_datablocks) + num_of_blocks;
    super_block->num_of_unallocated_datablocks = num;
    return 0;
}

int File_System_Manager::increment_inodecounter(){
    
    if ( super_block->inode_counter >= super_block->num_of_inodes ){
        return -1;
    }
    super_block->inode_counter++;
    //cout<< "Inode counter value" <<super_block->inode_counter<<endl;
    return super_block->inode_counter;
}

int File_System_Manager::get_inodecounter(){
    //cout<< "Inode counter value" <<super_block->inode_counter<<endl;
    return (super_block->inode_counter);
}

// method to see if al the inodes are filled
bool File_System_Manager::is_inode_full(){
    if ( super_block->num_of_unallocated_inodes == 0 ){
        return true;
    }
    return false;
    
}


int File_System_Manager::assignValueToInodeBitmap(int set_inode_bitmap){
    
    
    if (set_inode_bitmap== -1){
        return -1;
    }
    
    inode_bitmap[set_inode_bitmap] = 1;
    return 0;
    
}



int File_System_Manager::getFreeBitFromInodeBitmap(){
    
    
    
    for (int i=1 ; i < NUM_OF_INODES+1  ; i++){
        if ( inode_bitmap[i] == 0 ){
            return i;
        }
    }
    return -1;
}



int File_System_Manager::assignValueToDataBitmap(int data_bitmap_num){
    
    if (data_bitmap_num== -1){
        return -1;
    }
    
    data_bitmap[data_bitmap_num] = 1;
    return data_bitmap_num;
    
}


int File_System_Manager::getFreeDataBitFromDataBitmap(){
    
    
    
    for (int i=1 ; i < NUM_OF_DATABLOCKS+1 ; i++){
        if ( data_bitmap[i] == 0 ){
            //cout<<"The free bit is "<<i;
            return i;
        }
    }
    return -1;
}


int File_System_Manager::increment_datablock_counter(){
    
    if ( super_block->datablock_counter >= super_block->num_of_inodes ){
        return -1;
    }
    super_block->datablock_counter++;
    //cout<< "Inode counter value" <<super_block->inode_counter<<endl;
    return 0;
}

Inode* File_System_Manager::createNewInode(int inode_num ,char* name ){
    inode_array[inode_num] = new Inode(inode_num,name);
    return inode_array[inode_num] ;
}


char* File_System_Manager::getInodeArrayName(int count ){
    Inode* lInode = inode_array[count];
    if (lInode == NULL)
        cout<<"lInode is null "<<count<<endl;
    char* name =  inode_array[count]->getName() ;
    return name;
}

Inode*  File_System_Manager::getInodeInfo(int count){
    return inode_array[count];
}

void File_System_Manager::deallocateDataBlocksToTheFile(int datablock_num){
    
    
    // cout << "The datablock value is " << datablock_num<<endl;
    //cout << "The datablock value is " << datablock_array[datablock_num]<<endl;
    
    char* data_ptr = datablock_array[datablock_num];
    
    free(data_ptr);
    
    data_bitmap[datablock_num] = 0;
    
    
}


int File_System_Manager::writeDataBlock(int datablock_address , void* buf){
    
    strcpy (datablock_array[datablock_address],(char*) buf);
    
    return 0 ;
    
}

int File_System_Manager::freeInode(int inodeNum){
    
    inode_array[inodeNum]=NULL;
    inode_bitmap[inodeNum] = 0;
    
    return 0;
}

void File_System_Manager::printDataOftheFile(int inode_num){
    
    Inode* inode_vector = getInodeInfo(inode_num);
    
    if(!inode_vector){
        cout << "No Inode available "<<endl;
        return;
        
    }
    
    
    vector <int> inode_vector_value = inode_vector->getInodeVector();
    
    cout<<"The data stored in the file is "<<endl;
    for(int i =0 ; i< inode_vector_value.size() ; i++ ){
        
        //cout<<"the datablock index is "<<inode_vector_value.at(i);
        cout<< datablock_array[inode_vector_value.at(i)]<<endl;
    }
    
    
    
}

int File_System_Manager::allocateDataBlocksToTheFile(int data_block_num){
    
    char * data_ptr = NULL;
    data_ptr = (char *)malloc (4096);
    datablock_array[data_block_num] = data_ptr;
    
    
    
    return 0;
}





int File_System_Manager::increment_num_of_unallocated_inodes(){
    
    super_block->num_of_unallocated_inodes++;
    return 0;
    
}


int File_System_Manager::increment_num_of_unallocated_datablocks(){
    super_block->num_of_unallocated_datablocks++;
    return 0;
    
}


int File_System_Manager::decrement_inode_counter(){
    super_block->inode_counter--;
    return 0;
}

int File_System_Manager::decrement_datablock_counter(){
    super_block->datablock_counter--;
    return 0;
}




